package com.w.utils.date;
/**
 *
 **/

import com.w.utils.string.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateFormatUtils;

import java.lang.management.ManagementFactory;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.IntStream;

/**
 * @Author weiwei
 * @Date 2020-11-29 16:40
 * @description 时间工具类
 **/
@Slf4j
public class DateUtils extends org.apache.commons.lang3.time.DateUtils{


    public static String YYYY = "yyyy";

    public static String YYYY_MM = "yyyy-MM";

    public static String YYYY_MM_DD = "yyyy-MM-dd";

    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";

    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

    private static String[] parsePatterns = {
            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM",
            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};

    /**
     * 获取当前Date型日期
     *
     * @return Date() 当前日期
     */
    public static Date getNowDate()
    {
        return new Date();
    }

    /**
     * 获取当前日期, 默认格式为yyyy-MM-dd
     *
     * @return String
     */
    public static String getDate()
    {
        return dateTimeNow(YYYY_MM_DD);
    }

    public static final String getTime()
    {
        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
    }

    public static final String dateTimeNow()
    {
        return dateTimeNow(YYYYMMDDHHMMSS);
    }

    public static final String dateTimeNow(final String format)
    {
        return parseDateToStr(format, new Date());
    }

    public static final String dateTime(final Date date)
    {
        return parseDateToStr(YYYY_MM_DD, date);
    }

    public static final String parseDateToStr(final String format, final Date date)
    {
        return new SimpleDateFormat(format).format(date);
    }

    public static final Date dateTime(final String format, final String ts)
    {
        try
        {
            return new SimpleDateFormat(format).parse(ts);
        }
        catch (ParseException e)
        {
            throw new RuntimeException(e);
        }
    }

    /**
     * 日期路径 即年/月/日 如2018/08/08
     */
    public static final String datePath()
    {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyy/MM/dd");
    }

    /**
     * 日期路径 即年/月/日 如20180808
     */
    public static final String dateTime()
    {
        Date now = new Date();
        return DateFormatUtils.format(now, "yyyyMMdd");
    }

    /**
     * 日期型字符串转化为日期 格式
     */
    public static Date parseDate(Object str)
    {
        if (str == null)
        {
            return null;
        }
        try
        {
            return parseDate(str.toString(), parsePatterns);
        }
        catch (ParseException e)
        {
            return null;
        }
    }

    /**
     * 获取服务器启动时间
     */
    public static Date getServerStartDate()
    {
        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
        return new Date(time);
    }

    /**
     * 计算两个时间差
     */
    public static String getDatePoor(Date endDate, Date nowDate)
    {
        long nd = 1000 * 24 * 60 * 60;
        long nh = 1000 * 60 * 60;
        long nm = 1000 * 60;
        // long ns = 1000;
        // 获得两个时间的毫秒时间差异
        long diff = endDate.getTime() - nowDate.getTime();
        // 计算差多少天
        long day = diff / nd;
        // 计算差多少小时
        long hour = diff % nd / nh;
        // 计算差多少分钟
        long min = diff % nd % nh / nm;
        // 计算差多少秒//输出结果
        // long sec = diff % nd % nh % nm / ns;
        return day + "天" + hour + "小时" + min + "分钟";
    }

    /**
     * 时间转换,注意该方法添加了业务属性
     */
    public static String deliveryTime(Date startTm, Date endTm) {
        if(startTm!=null && endTm !=null ){
            SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
            String startTmStr = sdf.format(startTm);
            String endTmStr = sdf.format(endTm);
            return startTmStr + " - " + endTmStr;
        }else {
            return "";
        }
    }


    /**
     * 获取日期00:00:00
     * @return
     */
    public static Date getDayStart(Date date){
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        return calendar.getTime();
    }


    /**
     * 获取日期23:59:59
     * @return
     */
    public static Date getDayEnd(Date date){
        if(date == null){
            return null;
        }
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        return calendar.getTime();
    }

    /**
     *  Date转LocalDateTime
     */
    private static LocalDateTime getLocalDateTime(Date closeTm) {
        Instant instant = closeTm.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone);
    }

    /**
     * Date转LocalTime
     */
    private static LocalTime getLocalTime(Date closeTm) {
        Instant instant = closeTm.toInstant();
        ZoneId zone = ZoneId.systemDefault();
        return LocalDateTime.ofInstant(instant, zone).toLocalTime();
    }
    /**
     * 获取指定日期所在月第一天0点
     * @param date
     * @return
     */
    public static Date getMonthFirstDay(Date date){
        Calendar cale = Calendar.getInstance();
        cale.setTime(date);
        cale.set(Calendar.DAY_OF_MONTH, 1);
        cale.set(Calendar.HOUR_OF_DAY, 0);
        cale.set(Calendar.MINUTE, 0);
        cale.set(Calendar.SECOND, 0);
        return cale.getTime();
    }

    /**
     * 获取指定日期所在月最后一天23点59分59秒
     * @param date
     * @return
     */
    public static Date getMonthEndDay(Date date){
        Calendar cale = Calendar.getInstance();
        cale.setTime(date);
        cale.add(Calendar.MONTH, 1);
        cale.set(Calendar.DAY_OF_MONTH, 1);
        cale.add(Calendar.DAY_OF_MONTH, -1);
        cale.set(Calendar.HOUR_OF_DAY, 23);
        cale.set(Calendar.MINUTE, 59);
        cale.set(Calendar.SECOND, 59);
        return cale.getTime();
    }


    /**
     * 获取年数
     * @param date
     * @return
     */
    public static String getYear(Date date){
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return StringUtils.getString(instance.get(Calendar.YEAR));
    }

    /**
     * 获取月份有多少天
     * @param date
     * @return
     */
    public static int getMonthCount(Date date){
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        return instance.getActualMaximum(Calendar.DAY_OF_MONTH);
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    static class Time{
        private Date firstTime;
        private Date lastTime;
    }

    private static Map<Integer,Time> quarterMap ;

    static {
        initQuarterMap();
    }

    /**
     * 随便写一个年 使用的时候将年替换
     */
    private  static void initQuarterMap(){
        try {
            quarterMap = new HashMap<>();
            Time one = new Time(DateUtils.parseDate("2020-01-01 00:00:00",YYYY_MM_DD_HH_MM_SS),
                    DateUtils.parseDate("2020-03-31 23:59:59",YYYY_MM_DD_HH_MM_SS));
            Time two = new Time(DateUtils.parseDate("2020-04-01 00:00:00",YYYY_MM_DD_HH_MM_SS),
                    DateUtils.parseDate("2020-06-30 23:59:59",YYYY_MM_DD_HH_MM_SS));
            Time three = new Time(DateUtils.parseDate("2020-07-01 00:00:00",YYYY_MM_DD_HH_MM_SS),
                    DateUtils.parseDate("2020-09-30 23:59:59",YYYY_MM_DD_HH_MM_SS));
            Time four = new Time(DateUtils.parseDate("2020-10-01 00:00:00",YYYY_MM_DD_HH_MM_SS),
                    DateUtils.parseDate("2020-12-31 23:59:59",YYYY_MM_DD_HH_MM_SS));
            IntStream.rangeClosed(1,12).forEach(a->{
                Time data = null ;
                if (a>=1 && a <=3){
                    data =one;
                }
                if (a>=4 && a <=6){
                    data =two;
                }
                if (a>=7 && a <=9){
                    data =three;
                }
                if (a>=10 && a <=12){
                    data =four;
                }
                quarterMap.put(a,data);
            });
        }catch (Exception e){
            log.error("创建季度时间错误");
        }
    }

    /**
     * 获取季度第一天
     * @param date
     * @return
     */
    public static Date getQuarterFirst(Date date){
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        int y =instance.get(Calendar.YEAR);
        int m = instance.get(Calendar.MONTH)+1;
        if (quarterMap == null){
            initQuarterMap();
        }
        Date firstTime = quarterMap.get(m).firstTime;
        instance.setTime(firstTime);
        instance.set(Calendar.YEAR,y);
        return instance.getTime();
    }

    /**
     * 获取季度最后一天
     * @param date
     * @return
     */
    public static Date getQuarterLast(Date date){
        Calendar instance = Calendar.getInstance();
        instance.setTime(date);
        int y =instance.get(Calendar.YEAR);
        int m = instance.get(Calendar.MONTH)+1;
        if (quarterMap == null){
            initQuarterMap();
        }
        Date firstTime = quarterMap.get(m).lastTime;
        instance.setTime(firstTime);
        instance.set(Calendar.YEAR,y);
        return instance.getTime();
    }





    /**
     * 获取某年第一天日期0点
     *
     * @return Date
     */
    public static Date getYearFirst(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MONTH, 0);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        calendar.set(Calendar.HOUR_OF_DAY, 0);
        calendar.set(Calendar.MINUTE, 0);
        calendar.set(Calendar.SECOND, 0);
        calendar.set(Calendar.MILLISECOND,0);
        return calendar.getTime();
    }

    /**
     * 获取某年最后一天23点59分59秒
     *
     * @return Date
     */
    public static Date getYearLast(Date date) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.MONTH, 11);
        calendar.set(Calendar.DAY_OF_MONTH, 31);
        calendar.set(Calendar.HOUR_OF_DAY, 23);
        calendar.set(Calendar.MINUTE, 59);
        calendar.set(Calendar.SECOND, 59);
        calendar.set(Calendar.MILLISECOND,999);
        return calendar.getTime();
    }

    public static String[]  weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
    public static String[]  month = {"一月", "二月", "三月", "四月", "五月", "六月", "七月","八月","九月","十月","十一月","十二月"};

    /**
     * 获取几月几日
     * @param date
     * @return
     */
    public static String dayToLabel(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        StringBuilder sb = new StringBuilder();
        sb.append(cal.get(Calendar.MONTH)+1);
        sb.append("月");
        sb.append(cal.get(Calendar.DAY_OF_MONTH));
        sb.append("日");
        return sb.toString();
    }


    /**
     * 获取星期几
     * @param date
     * @return
     */
    public static String dayToWeek(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return weekDays[cal.get(Calendar.DAY_OF_WEEK) - 1];
    }

    /**
     * 获取几月
     * @param date
     * @return
     */
    public static String dayToMonth(Date date){
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        return month[cal.get(Calendar.MONTH)];
    }

    /**
     * 获取本周的第一天
     * @return String
     * **/
    public static Date getWeekStart(){
        Calendar cal=Calendar.getInstance();
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.setTime(new Date());
        cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek()); // Monday
        cal.set(Calendar.HOUR_OF_DAY, 0);
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND,0);
        return cal.getTime();
    }
    /**
     * 获取本周的最后一天
     * @return String
     * **/
    public static Date getWeekEnd(){
        Calendar cal=Calendar.getInstance();
        cal.setFirstDayOfWeek(Calendar.MONDAY);
        cal.setTime(new Date());
        cal.set(Calendar.DAY_OF_WEEK, cal.getFirstDayOfWeek() + 6); // Sunday
        cal.set(Calendar.HOUR_OF_DAY, 23);
        cal.set(Calendar.MINUTE, 59);
        cal.set(Calendar.SECOND, 59);
        cal.set(Calendar.MILLISECOND,999);
        return cal.getTime();
    }

    /**
     * 计算时间相隔天数
     * @param endTime  ： 结束时间
     * @param startTime ： 开始时间
     *
     * @return
     */
    public static int caculateTotalTime(Date endTime,Date startTime) {
        long ts = endTime.getTime();
        long ts1 = startTime.getTime();
        int result =(int) ((ts - ts1) / (1000*3600*24));
        return result;
    }

    /**
     * 常用时间筛选转化,目前支持y , y-m 两种
     * @param timeType
     * @param year
     * @param month
     * @return
     */
    public static Map<String, Date> getTimeByYOrM(String timeType, Integer year, Integer month) {
        Map<String, Date> result = new HashMap<>();
        Calendar calendar =Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.set(Calendar.YEAR,year);
        if(month != null){
            calendar.set(Calendar.MONTH,month- 1);
        }
        Date time = calendar.getTime();
        switch (timeType){
            case "y":
                result.put("startTime",getYearFirst(time));
                result.put("endTime",getYearLast(time));
                break;
            case "m":
                result.put("startTime",getMonthFirstDay(time));
                result.put("endTime",getMonthEndDay(time));
                break;
        }
        return result;
    }
}
